/**
 * (c) 2014 StreamSets, Inc. All rights reserved. May not
 * be copied, modified, or distributed in whole or part without
 * written consent of StreamSets, Inc.
 */
package com.streamsets.pipeline.stage.processor.javascript;

import com.streamsets.pipeline.api.ConfigDef;
import com.streamsets.pipeline.api.ConfigGroups;
import com.streamsets.pipeline.api.GenerateResourceBundle;
import com.streamsets.pipeline.api.Processor;
import com.streamsets.pipeline.api.StageDef;
import com.streamsets.pipeline.api.ValueChooser;
import com.streamsets.pipeline.configurablestage.DProcessor;
import com.streamsets.pipeline.stage.processor.scripting.ProcessingMode;
import com.streamsets.pipeline.stage.processor.scripting.ProcessingModeChooserValues;

@StageDef(
    version = "1.0.0",
    label = "JavaScript Evaluator",
    description = "Processes records using JavaScript",
    icon="javascript.png"
)
@ConfigGroups(Groups.class)
@GenerateResourceBundle
public class JavaScriptDProcessor extends DProcessor {

  @ConfigDef(
      required = true,
      type = ConfigDef.Type.MODEL,
      defaultValue = "BATCH",
      label = "Record Processing Mode",
      description = "If 'Record by Record' the processor takes care of record error handling, if 'Batch by Batch' " +
                    "the JavaScript must take care of record error handling",
      displayPosition = 10,
      group = "JAVASCRIPT"
  )
  @ValueChooser(ProcessingModeChooserValues.class)
  public ProcessingMode processingMode;

  private static final String DEFAULT_SCRIPT =
    "/**\n" +
    " * Sample JavaScript code\n" +
    " *\n" +
    " * Available Objects:\n" +
    " * \n" +
    " *  records: an array of records to process, depending on the JavaScript processor\n" +
    " *           processing mode it may have 1 record or all the records in the batch.\n" +
    " *\n" +
    " *  state: a dict that is preserved between invocations of this script. \n" +
    " *        Useful for caching bits of data e.g. counters.\n" +
    " *\n" +
    " *  log.<loglevel>(msg, obj...): use instead of print to send log messages to the log4j log instead of stdout.\n" +
    " *                               loglevel is any log4j level: e.g. info, error, warn, trace.\n" +
    " *\n" +
    " *  out.write(record): writes a record to processor output\n" +
    " *\n" +
    " *  err.write(record, message): sends a record to error\n" +
    " *\n" +
    " */\n" +
    "\n" +
    "for(var i = 0; i < records.length; i++) {\n" +
    "  try {\n" +
    "    // Change record root field value to a STRING value\n" +
    "    //records[i].value = 'Hello ' + i;\n" +
    "\n" +
    "\n" +
    "    // Change record root field value to a MAP value and create an entry\n" +
    "    //records[i].value = {};\n" +
    "    //records[i].value.V = 'Hello';\n" +
    "\n" +
    "    // Modify a MAP entry\n" +
    "    //records[i].value.V = 5;\n" +
    "\n" +
    "    // Create an ARRAY entry\n" +
    "    //records[i].value.A = [];\n" +
    "    //records[i].value.A.push('Element 1');\n" +
    "    //records[i].value.A.push('Element 2');\n" +
    "\n" +
    "    // Modify an existing ARRAY entry\n" +
    "    //records[i].value.A[0] = 100;\n" +
    "\n" +
    "    // Write record to procesor output\n" +
    "    out.write(records[i]);\n" +
    "  } catch (e) {\n" +
    "    // Send record to error\n" +
    "    err.write(records[i], e);\n" +
    "  }\n" +
    "}\n";

  @ConfigDef(
      required = true,
      type = ConfigDef.Type.TEXT,
      defaultValue = DEFAULT_SCRIPT,
      label = "Script",
      displayPosition = 20,
      group = "JAVASCRIPT",
      mode = ConfigDef.Mode.JAVASCRIPT
  )
  public String script;

  @Override
  protected Processor createProcessor() {
    return new JavaScriptProcessor(processingMode, script);
  }

}
